
package com.hlkj.pay.app.merchant.ext.impl.baofu;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.io.IOException;
import java.util.*;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.id.IdUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.ChannelMerchantPaymentExtPt;
import com.hlkj.pay.app.merchant.ext.MerchantExtConstant;
import com.hlkj.pay.app.merchant.ext.dto.payment.ChannelPaymentAccountContext;
import com.hlkj.pay.app.merchant.ext.dto.payment.ChannelPaymentCallBackContext;
import com.hlkj.pay.app.merchant.ext.dto.payment.ChannelPaymentCallBackDto;
import com.hlkj.pay.app.merchant.ext.dto.payment.ChannelPaymentContext;
import com.hlkj.pay.app.merchant.ext.impl.baofu.dto.BaoFuConfig;
import com.hlkj.pay.app.merchant.ext.impl.baofu.dto.BoaFuAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.baofu.dto.res.*;
import com.hlkj.pay.app.merchant.ext.impl.baofu.handler.BaoFuMerchantParamsHandle;
import com.hlkj.pay.app.merchant.ext.impl.baofu.handler.BaofuMerchantCommonParamsHandle;
import com.hlkj.pay.app.merchant.ext.impl.baofu.util.BaoFuFileZipUtil;
import com.hlkj.pay.app.merchant.ext.impl.baofu.util.BaoFuSigner;
import com.hlkj.pay.dto.merchant.MerchantAcctBalanceDto;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.pay.PayChannelRequestDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.infrastructure.model.payment.MerchantPaymentDetailDO;
import com.hlkj.pay.util.HttpRequestUtil;
import com.hlkj.pay.util.MerchantUtils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/11/20 17:19
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = MerchantExtConstant.CHANNEL_BAOFU)
public class BaoFuPaymentExtPt implements ChannelMerchantPaymentExtPt {

    private final BaofuMerchantCommonParamsHandle baofuMerchantCommonParamsHandle;

    private final BaoFuMerchantParamsHandle baoFuMerchantParamsHandle;

    @Override
    public void submitChannelSinglePayment(ChannelPaymentContext channelPayOrderContext) {
        // todo 后期修改为虚拟户转账
        log.info("宝付提交单笔代付 detailPaymentId:{}", channelPayOrderContext.getMerchantPaymentDetailDO().getDetailPaymentId());
        MerchantPaymentDetailDO merchantPaymentDetailDO = channelPayOrderContext.getMerchantPaymentDetailDO();
        CommonResult<BaoFuConfig> configCommonResult = baofuMerchantCommonParamsHandle.baoFuConfig(channelPayOrderContext.getProviderChannelConfig(),
                channelPayOrderContext.isTest());
        if (!configCommonResult.isSuccess()) {
            channelPayOrderContext.setRemark(configCommonResult.getMsg());
            channelPayOrderContext.setProcessStatus(false);
            return;
        }
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();
        BoaFuAppChannelParams payAppChannelParams = payAppChannelParams(merchantAppChannelDO);
        try {
            PayChannelRequestDO payChannelRequestDO = new PayChannelRequestDO();
            Map<String, Object> params = new HashMap<>();
            params.put("wallet_no", payAppChannelParams.getWalletNo());
            params.put("card_no", merchantPaymentDetailDO.getCardNo());
            params.put("card_name", merchantPaymentDetailDO.getName());
            params.put("order_amount", MerchantUtils.YuanToFen(merchantPaymentDetailDO.getPayAmount()));
            params.put("settle_id", merchantPaymentDetailDO.getBranchCode());
            params.put("legal_idcard", merchantPaymentDetailDO.getCertNo());
            params.put("mobile", merchantPaymentDetailDO.getCardPhone());
            params.put("summary", merchantPaymentDetailDO.getRemark());

            payChannelRequestDO.setRequestParams(JsonUtils.toJsonString(params));
            // 再提交数据
            CommonResult<BaoFuCommonRes> commonResult = baofuMerchantCommonParamsHandle.request(params, merchantPaymentDetailDO.getDetailPaymentId(), "2212",
                    channelPayOrderContext.getNotifyUrl(), configCommonResult.getData(), channelPayOrderContext.isTest());
            payChannelRequestDO.setResponse(JsonUtils.toJsonString(commonResult));
            channelPayOrderContext.setPayChannelRequestDO(payChannelRequestDO);
            if (!commonResult.isSuccess()) {
                channelPayOrderContext.setRemark(commonResult.getMsg());
                channelPayOrderContext.setProcessStatus(false);
                return;
            }
            BaoFuCommonRes baoFuCommonRes = commonResult.getData();
            String data = baoFuCommonRes.getData();
            if (!StringUtils.hasText(data)) {
                channelPayOrderContext.setRemark(baoFuCommonRes.getResp_msg());
                channelPayOrderContext.setProcessStatus(false);
                return;
            }
            BaoFuPaymentSubmitRes baoFuPaymentSubmitRes = JsonUtils.parseObject(data, BaoFuPaymentSubmitRes.class);
            if ("FAIL".equals(baoFuPaymentSubmitRes.getStatus())) {
                log.info("宝付提交单笔代付 返回失败:{}", baoFuPaymentSubmitRes.getStatus_msg());
                channelPayOrderContext.setProcessStatus(false);
            }
            channelPayOrderContext.setRemark(baoFuPaymentSubmitRes.getStatus_msg());
        }
        catch (Exception e) {
            channelPayOrderContext.setProcessStatus(false);
            channelPayOrderContext.setRemark(e.getMessage());
        }

    }

    @Override
    public void queryChannelAccount(ChannelPaymentAccountContext channelPayOrderContext) {
        CommonResult<BaoFuConfig> configCommonResult = baofuMerchantCommonParamsHandle.baoFuConfig(channelPayOrderContext.getProviderChannelConfig(),
                channelPayOrderContext.isTest());
        if (!configCommonResult.isSuccess()) {
            channelPayOrderContext.setRemark(configCommonResult.getMsg());
            channelPayOrderContext.setProcessStatus(false);
            return;
        }
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();
        BoaFuAppChannelParams payAppChannelParams = payAppChannelParams(merchantAppChannelDO);
        try {
            Map<String, Object> params = new HashMap<>();
            List<Integer> acctTypeList = channelPayOrderContext.getAcctTypeList();
            if (acctTypeList == null) {
                acctTypeList = new ArrayList<>();
                acctTypeList.add(1);
                acctTypeList.add(2);
            }
            List<MerchantAcctBalanceDto> merchantAcctBalances = new ArrayList<>();
            acctTypeList.stream().forEach(acctType -> {
                params.put("wallet_no", payAppChannelParams.getWalletNo());
                params.put("type", acctType);
                String requestId = IdUtils.getSnowflakeNextIdStr();
                // 再提交数据
                CommonResult<BaoFuCommonRes> commonResult = baofuMerchantCommonParamsHandle.request(params, requestId, "2204", null, configCommonResult.getData(),
                        channelPayOrderContext.isTest());
                if (!commonResult.isSuccess()) {
                    channelPayOrderContext.setRemark(commonResult.getMsg());
                    channelPayOrderContext.setProcessStatus(false);
                    return;
                }
                BaoFuCommonRes baoFuCommonRes = commonResult.getData();
                String data = baoFuCommonRes.getData();
                if (!StringUtils.hasText(data)) {
                    channelPayOrderContext.setRemark(baoFuCommonRes.getResp_msg());
                    channelPayOrderContext.setProcessStatus(false);
                    return;
                }
                BaoFuBalanceQueryRes baoFuBalanceQueryRes = JsonUtils.parseObject(data, BaoFuBalanceQueryRes.class);
                MerchantAcctBalanceDto merchantAcctBalanceDto = new MerchantAcctBalanceDto();
                merchantAcctBalanceDto.setBalance(MerchantUtils.fenToYuan(baoFuBalanceQueryRes.getBalance()));
                merchantAcctBalanceDto.setAcctType(acctType);
                merchantAcctBalances.add(merchantAcctBalanceDto);
            });
            channelPayOrderContext.setMerchantAcctBalances(merchantAcctBalances);
        }
        catch (Exception e) {
            channelPayOrderContext.setProcessStatus(false);
            channelPayOrderContext.setRemark(e.getMessage());
        }
    }

    @Override
    public void queryChannelPayment(ChannelPaymentContext channelPayOrderContext) {
        log.info("宝付查询单笔代付 detailPaymentId:{}", channelPayOrderContext.getMerchantPaymentDetailDO().getDetailPaymentId());
        MerchantPaymentDetailDO merchantPaymentDetailDO = channelPayOrderContext.getMerchantPaymentDetailDO();
        CommonResult<BaoFuConfig> configCommonResult = baofuMerchantCommonParamsHandle.baoFuConfig(channelPayOrderContext.getProviderChannelConfig(),
                channelPayOrderContext.isTest());
        if (!configCommonResult.isSuccess()) {
            channelPayOrderContext.setRemark(configCommonResult.getMsg());
            channelPayOrderContext.setProcessStatus(false);
            return;
        }
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();
        BoaFuAppChannelParams payAppChannelParams = payAppChannelParams(merchantAppChannelDO);
        try {
            PayChannelRequestDO payChannelRequestDO = new PayChannelRequestDO();
            Map<String, Object> params = new HashMap<>();
            params.put("orig_client_trans_id", merchantPaymentDetailDO.getDetailPaymentId());

            payChannelRequestDO.setRequestParams(JsonUtils.toJsonString(params));
            // 再提交数据
            CommonResult<BaoFuCommonRes> commonResult = baofuMerchantCommonParamsHandle.request(params, merchantPaymentDetailDO.getDetailPaymentId(), "2207",
                    channelPayOrderContext.getNotifyUrl(), configCommonResult.getData(), channelPayOrderContext.isTest());
            payChannelRequestDO.setResponse(JsonUtils.toJsonString(commonResult));
            channelPayOrderContext.setPayChannelRequestDO(payChannelRequestDO);
            if (!commonResult.isSuccess()) {
                channelPayOrderContext.setRemark(commonResult.getMsg());
                channelPayOrderContext.setProcessStatus(false);
                return;
            }
            BaoFuCommonRes baoFuCommonRes = commonResult.getData();
            String data = baoFuCommonRes.getData();
            MerchantPaymentDetailDO updateTransferOrderDO = new MerchantPaymentDetailDO();
            channelPayOrderContext.setUpdateMerchantPaymentDetailDO(updateTransferOrderDO);
            if (!StringUtils.hasText(data)) {
                channelPayOrderContext.setRemark(baoFuCommonRes.getResp_msg());
                channelPayOrderContext.setProcessStatus(false);
                log.info("宝付查询单笔代付返回没有详情 直接失败 detailPaymentId:{}", channelPayOrderContext.getMerchantPaymentDetailDO().getDetailPaymentId());
                updateTransferOrderDO.setStatus(MerchantEnum.PROCESS_STATUS.FAIL.getCode());
                channelPayOrderContext.setRemark(baoFuCommonRes.getResp_msg());
                return;
            }
            BaoFuPaymentQueryRes baoFuPaymentSubmitRes = JsonUtils.parseObject(data, BaoFuPaymentQueryRes.class);
            // INIT 初始化 PROCESSING处理中 SUCCESS成功 FAIL失败
            switch (baoFuPaymentSubmitRes.getStatus()) {
                case "FAIL":
                    updateTransferOrderDO.setStatus(MerchantEnum.PROCESS_STATUS.FAIL.getCode());
                    break;
                case "SUCCESS":
                    updateTransferOrderDO.setStatus(MerchantEnum.PROCESS_STATUS.SUCCESS.getCode());
                    updateTransferOrderDO.setRemark(baoFuPaymentSubmitRes.getStatus_msg());
                    break;
                default:
                    updateTransferOrderDO.setStatus(MerchantEnum.PROCESS_STATUS.DOING.getCode());
            }

        }
        catch (Exception e) {
            channelPayOrderContext.setProcessStatus(false);
            channelPayOrderContext.setRemark(e.getMessage());
        }
    }

    @Override
    public void queryChannelPaymentProof(ChannelPaymentContext channelPayOrderContext) {
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();
        log.info("宝付查询付款凭证 detailPaymentId:{}", merchantAppChannelDO.getCode());
        MerchantPaymentDetailDO merchantPaymentDetailDO = channelPayOrderContext.getMerchantPaymentDetailDO();
        CommonResult<BaoFuConfig> configCommonResult = baofuMerchantCommonParamsHandle.baoFuConfig(channelPayOrderContext.getProviderChannelConfig(),
                channelPayOrderContext.isTest());
        if (!configCommonResult.isSuccess()) {
            channelPayOrderContext.setRemark(configCommonResult.getMsg());
            channelPayOrderContext.setProcessStatus(false);
            return;
        }
        BoaFuAppChannelParams payAppChannelParams = payAppChannelParams(merchantAppChannelDO);
        try {
            PayChannelRequestDO payChannelRequestDO = new PayChannelRequestDO();
            Map<String, Object> params = new HashMap<>();
            params.put("orig_client_trans_id", merchantPaymentDetailDO.getDetailPaymentId());
            params.put("wallet_no", merchantPaymentDetailDO.getDetailPaymentId());
            // 2-提现(宝付代付到银行卡)
            // 8-调拨(银行到宝付)
            // 4-银行入金
            params.put("type", "2");

            payChannelRequestDO.setRequestParams(JsonUtils.toJsonString(params));
            // 再提交数据
            CommonResult<BaoFuCommonRes> commonResult = baofuMerchantCommonParamsHandle.request(params, merchantPaymentDetailDO.getDetailPaymentId(), "2301",
                    channelPayOrderContext.getNotifyUrl(), configCommonResult.getData(), channelPayOrderContext.isTest());
            payChannelRequestDO.setResponse(JsonUtils.toJsonString(commonResult));
            channelPayOrderContext.setPayChannelRequestDO(payChannelRequestDO);
            if (!commonResult.isSuccess()) {
                channelPayOrderContext.setRemark(commonResult.getMsg());
                channelPayOrderContext.setProcessStatus(false);
                return;
            }
            BaoFuCommonRes baoFuCommonRes = commonResult.getData();
            String data = baoFuCommonRes.getData();
            MerchantPaymentDetailDO updateTransferOrderDO = new MerchantPaymentDetailDO();
            channelPayOrderContext.setUpdateMerchantPaymentDetailDO(updateTransferOrderDO);
            if (!StringUtils.hasText(data)) {
                channelPayOrderContext.setRemark(baoFuCommonRes.getResp_msg());
                channelPayOrderContext.setProcessStatus(false);
                return;
            }
            BaoFuPaymentProofQueryRes baoFuPaymentSubmitRes = JsonUtils.parseObject(data, BaoFuPaymentProofQueryRes.class);
            // INIT 初始化 PROCESSING处理中 SUCCESS成功 FAIL失败
            switch (baoFuPaymentSubmitRes.getStatus()) {
                case "FAIL":
                    channelPayOrderContext.setProcessStatus(false);
                    channelPayOrderContext.setRemark("宝付获取凭证失败");
                    break;
                default:
                    byte[] bb = Base64.getDecoder().decode(baoFuPaymentSubmitRes.getContent());
                    byte[] ff = BaoFuFileZipUtil.unzip(bb);
                    channelPayOrderContext.setVoucherFileByte(ff);
            }
        }
        catch (Exception e) {
            channelPayOrderContext.setProcessStatus(false);
            channelPayOrderContext.setRemark(e.getMessage());
        }
    }

    @Override
    public ChannelPaymentCallBackDto parseCallBackText(ChannelPaymentCallBackContext channelPaymentCallBackContext, HttpServletRequest request) {
        ChannelPaymentCallBackDto channelPaymentCallBackDto = new ChannelPaymentCallBackDto();
        ProviderChannelConfigDO providerChannelConfigDO = channelPaymentCallBackContext.getProviderChannelConfig();
        CommonResult<BaoFuConfig> configCommonResult = baofuMerchantCommonParamsHandle.baoFuConfig(providerChannelConfigDO, true);
        if (!configCommonResult.isSuccess()) {
            channelPaymentCallBackDto.setRemark(configCommonResult.getMsg());
            channelPaymentCallBackDto.setProcessStatus(false);
            return channelPaymentCallBackDto;
        }
        BaoFuConfig baoFuConfig = configCommonResult.getData();
        Map<String, String> params = HttpRequestUtil.requestFormParams(request);
        String results = JsonUtils.toJsonString(params);
        log.info("宝付回调资金调拨结果通知 响应结果 results:{}", results);
        Boolean bool = baofuMerchantCommonParamsHandle.verifyByCerFile(results, baoFuConfig);
        if (!bool) {
            channelPaymentCallBackDto.setVerifySign(false);
        }
        BaoFuCommonRes baoFuCommonRes = JsonUtils.parseObject(results, BaoFuCommonRes.class);
        log.info("宝付代付结果通知 验签结果:" + bool);
        String data = null;
        try {
            data = BaoFuSigner.Base64Decode(params.get("data"));
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("宝付代付结果通知 业务响应结果 data :{}", data);
        MerchantPaymentDetailDO updateTransferOrderDO = new MerchantPaymentDetailDO();
        channelPaymentCallBackDto.setMerchantPaymentDetailDO(updateTransferOrderDO);
        if (!StringUtils.hasText(data)) {
            channelPaymentCallBackDto.setRemark(baoFuCommonRes.getResp_msg());
            channelPaymentCallBackDto.setProcessStatus(false);
            return channelPaymentCallBackDto;
        }
        BaoFuPaymentQueryRes baoFuPaymentSubmitRes = JsonUtils.parseObject(data, BaoFuPaymentQueryRes.class);
        updateTransferOrderDO.setDetailPaymentId(params.get("client_trans_id"));
        // INIT 初始化 PROCESSING处理中 SUCCESS成功 FAIL失败
        switch (baoFuPaymentSubmitRes.getStatus()) {
            case "FAIL":
                updateTransferOrderDO.setStatus(MerchantEnum.PROCESS_STATUS.FAIL.getCode());
                break;
            case "SUCCESS":
                updateTransferOrderDO.setStatus(MerchantEnum.PROCESS_STATUS.SUCCESS.getCode());
                updateTransferOrderDO.setRemark(baoFuPaymentSubmitRes.getStatus_msg());
                break;
            default:
                updateTransferOrderDO.setStatus(MerchantEnum.PROCESS_STATUS.DOING.getCode());
        }
        return channelPaymentCallBackDto;
    }

    @Override
    public ChannelPaymentCallBackDto parseCallBackTextFix(HttpServletRequest accessCallBody) {
        // 宝付 参数解析方法为parseCallBackTextF
        return null;
    }

    @Override
    public String processCallBack(MerchantAppChannelDO merchantAppChannelDO, CommonResult commonResult) {
        Map<String, Object> callParams = new HashMap<>();
        if (commonResult.isSuccess()) {
            callParams.put("resp_code", "00000000");
            callParams.put("resp_msg", "success");
        }
        else {
            callParams.put("resp_code", commonResult.getCode());
            callParams.put("resp_msg", commonResult.getMsg());
        }
        return JsonUtils.toJsonString(callParams);
    }

    @Override
    public Boolean verify(ProviderChannelConfigDO providerChannelConfigDO, MerchantAppChannelDO merchantAppChannelDO, String accessCallBody) {
        // 宝付 回调地址包含通道信息 数据解析时已经验签
        return null;
    }

    @Override
    public void notifyChannel(ChannelPaymentContext channelPaymentContext) {

    }

    @Override
    public void submitChannelSingleRecharge(ChannelPaymentContext channelPaymentContext) {

    }

    @Override
    public void notifyProofGenerate(ChannelPaymentContext channelPaymentContext) {

    }

    private BoaFuAppChannelParams payAppChannelParams(MerchantAppChannelDO merchantAppChannelDO) {
        return JsonUtils.parseObject(merchantAppChannelDO.getAppConfigJson(), BoaFuAppChannelParams.class);
    }

}
